using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.ServiceModel;

namespace InfFront.UICore
{

    /// <summary>
    /// UICore data providing interface. 
    /// Is used by the UI controls to access to data field definitions and values.
    /// </summary>
    [ServiceContract(Namespace = "http://InfFront.UICore")]
    public interface IInfoSource
    {
        /// <summary>
        /// Unique (within the parent InfoSource) InfoSource name
        /// </summary>
        [OperationContract]
        string GetName();

        /// <summary>
        /// IInfoSource's title (couple words)
        /// </summary>
        [OperationContract]
        string GetTitle();

        /// <summary>
        /// InfoSource field descriptors
        /// </summary>
        [OperationContract]
        IInfoFieldList GetFields();

        /// <summary>
        /// InfoSource command descriptors
        /// </summary>
        [OperationContract]
        IInfoCommandList GetCommands();

        /// <summary>
        /// Max InfoSource item count (return -1 if it's unknown)
        /// </summary>
        [OperationContract]
        int GetMaxEntryCount();

        /// <summary>
        /// If the InfoSource has it's own information or it acts only as a child InfoSource holder (see the GetChildSources method)
        /// </summary>
        [OperationContract]
        bool GetIsDummy();

        /// <summary>
        /// Name of the InfoCommand to be executed when user doubleclicks a grid row
        /// </summary>
        [OperationContract]
        string GetListDoubleClickCommandName();

        /// <summary>
        /// Name of the InfoField which is to be used to retrieve record icons at the ListView/Icon List modes
        /// </summary>
        [OperationContract]
        string GetIconFieldName();

        /// <summary>
        /// Name of the InfoField which is to be used to retrieve record titles at the ListView/Icon List modes
        /// </summary>
        [OperationContract]
        string GetTitleFieldName();

        /// <summary>
        /// If the inplace (in a grid cell, for instance) entry editing is allowed
        /// </summary>
        [OperationContract]
        bool GetAllowsInplaceEdit();

        /// <summary>
        /// If editing of the InfoSource entries must be buffered (with Cancel/Apply buttons)
        /// </summary>
        [OperationContract]
        bool GetNeedsEditBuffer();

        /// <summary>
        /// Get an image
        /// </summary>
        /// <param name="hSize">Icon horizontal size (16, 24, 32, 72, 128 or other)</param>
        /// <param name="vSize">Icon vertical size (16, 24, 32, 72, 128 or other)</param>
        /// <param name="style">Style of the icon</param>
        /// <param name="entry">A record for which we want the icon to be retrieved (leave it *null* if you're to get main InfoSource's icon)</param>
        /// <param name="fieldName">A field for which we want the icon to be retrieved (leave it *null* if you're to get main record's or InfoSource's icon)</param>
        /// <returns>IImage instance</returns>
        [OperationContract]
        IImage GetImage(int hSize, int vSize, IconStyle style, IInfoEntry entry, string fieldName);

        /// <summary>
        /// Get parametrized list of entries
        /// </summary>
        /// <param name="sortFieldNames">The field names to sort by</param>
        /// <param name="sortFieldDirections">The sort directions for the *sortFieldNames*</param>
        /// <returns>IInfoEntries instance</returns>
        [OperationContract]
        IInfoEntries GetEntries(int maxCount, string[] filterFieldNames, object[] filterValues,
                                string[] sortFieldNames, ListSortDirection[] sortFieldDirections);

        /// <summary>
        /// If the *GetEntries* supports sorting parameters
        /// </summary>
        [OperationContract]
        bool GetSupportsSorting();

        /// <summary>
        /// Entry data retrieval interface
        /// </summary>
        /// <param name="entry">the data entry reference</param>
        /// <param name="fieldNames">requested field names</param>
        /// <returns>for an *entry* specified it returns the read-only stream containing packed values data of *fieldNames*.</returns>
        /// <returns>Use the *InfFront.UICore.Helpers.FieldDataUnpacker* to parse the stream.</returns>
        [OperationContract]
        Stream GetData(IInfoEntry entry, string[] fieldNames);

        /// <summary>
        /// Entry data input interface
        /// </summary>
        /// <param name="entry">the data entry reference</param>
        /// <param name="fieldNames">updated fields descriptors</param>
        /// <param name="data">Stream containing data of the *fieldNames* specified</param>
        /// <param name="data">Use the *InfFront.UICore.Helpers.FieldDataPacker* to pack the field values</param>
        /// <returns>Update field values of the *entry* according to *fieldNames* and *data* provided</returns>
        [OperationContract]
        void SetData(IInfoEntry entry, string[] fieldNames, Stream data);

        /// <summary>
        /// Create an InfoCommand execution presenter
        /// </summary>
        /// <param name="args">execution context</param>
        [OperationContract]
        IExecutionControl ExecuteCommand(IExecuteCommandArgs args);

        /// <summary>
        /// Checks if the commands are actually enable
        /// </summary>
        /// <param name="currentEntry">currently selected entry</param>
        /// <param name="commandNames">names of the commands</param>
        /// <returns>bool array containing statuses for each command requested by the *commandNames*</returns>
        [OperationContract]
        bool[] CheckCommandsEnabled(IInfoEntry currentEntry, string[] commandNames);

        /// <summary>
        /// Child InfoSources
        /// </summary>
        [OperationContract]
        IInfoSourceList GetChildSources();

        #region Callbacks
        /// <summary>
        /// Register/Unregister event handlers
        /// </summary>
        /// <param name="args">parameters</param>
        [OperationContract]
        void SetCallbacks(IInfoSourceSetCallbacksArgs args);
        #endregion
    }

    /// <summary>
    /// InfoSource bookmark interface. Used for enumeration over InfoSource entries.
    /// </summary>
    [ServiceContract(Namespace = "http://InfFront.UICore")]
    public interface IInfoEntry : IDisposable
    {
    }

    /// <summary>
    /// IInfoEntry list
    /// </summary>
    [ServiceContract(Namespace = "http://InfFront.UICore")]
    public interface IInfoEntries : IEnumerable<IInfoEntry>
    {
        /// <summary>
        /// Create a new enumerator over InfoSource entries
        /// </summary>
        /// <param name="position">entry to make it current</param>
        /// <returns>a new IInfoSourceEnumerator</returns>
        [OperationContract]
        IInfoSourceEnumerator GetEnumerator(IInfoEntry position);

        /// <summary>
        /// entry count
        /// </summary>
        [OperationContract]
        int GetCount();

        /// <summary>
        /// An entry by index
        /// </summary>
        /// <param name="index">the index</param>
        /// <returns>the entry</returns>
        [OperationContract]
        IInfoEntry GetItem(int index);

        /// <summary>
        /// Find out the index of the entry
        /// </summary>
        /// <param name="entry">the entry</param>
        /// <returns>the index</returns>
        [OperationContract]
        int IndexOf(IInfoEntry entry);

        /// <summary>
        /// Sequential entry data retrieval interface
        /// </summary>
        /// <param name="args">arguments</param>
        /// <returns>for every record from *args.Begin* to *args.End* it returns the read-only stream containing packed values data of *args.FieldNames*.</returns>
        /// <returns>Use the *InfFront.UICore.Helpers.FieldDataUnpacker* to parse the stream.</returns>
        [OperationContract]
        Stream GetData(IInfoEntriesGetDataArgs args);
    }

    // TODO: Consider converting the IInfoEntriesGetDataArgs (and all other *Args interfaces) to a structure, to improve (?) service call performance. Or should we just transfer all the IInfoSourceGetIconArgs' members as regular GetData parameters instead?

    /// <summary>
    /// General InfoSource entry enumeration interface.
    /// </summary>
    [ServiceContract(Namespace = "http://InfFront.UICore")]
    public interface IInfoSourceEnumerator : IEnumerator<IInfoEntry>
    {
        /// <summary>
        /// Move enumerator over several steps forward or backward
        /// </summary>
        /// <param name="steps">count of steps to move on (may be negative)</param>
        /// <returns>count of steps actually made</returns>
        [OperationContract]
        int MoveNext(int steps);
    }

    /// <summary>
    /// Arguments for the IInfoEntries.GetData method
    /// </summary>
    [ServiceContract(Namespace = "http://InfFront.UICore")]
    public interface IInfoEntriesGetDataArgs
    {
        /// <summary>
        /// Starting bookmark
        /// </summary>
        [OperationContract]
        IInfoEntry GetBegin();

        /// <summary>
        /// Finishing bookmark
        /// </summary>
        [OperationContract]
        IInfoEntry GetEnd();

        /// <summary>
        /// requested field names
        /// </summary>
        [OperationContract]
        string[] GetFieldNames();
    }

    /// <summary>
    /// InfoSource event handlers
    /// </summary>
    [ServiceContract(Namespace = "http://InfFront.UICore")]
    public interface IInfoSourceCallbacks
    {
        /// <summary>
        /// Method is invoked every time the InfoSource is dramatically changed (all fields, groups, commands etc. are to be realoaded)
        /// </summary>
        [OperationContract]
        void OnSourceRebuilt();

        /// <summary>
        /// Method is invoked every time the InfoSource has some changed entries
        /// </summary>
        /// <param name="entry">the changed entry (null means that the entire list has to be refreshed)</param>
        [OperationContract]
        void OnSourceEntryRefreshed(IInfoEntry entry);

        /// <summary>
        /// Opens an entry editing dialog (or a wizard or whatever) 
        /// </summary>
        /// <param name="entry">the entry to be edited</param>
        [OperationContract]
        void BeginEntryEdit(IInfoEntry entry);

        /// <summary>
        /// Opens an entry creation dialog (or a wizard or whatever) 
        /// </summary>
        /// <param name="entry">the entry stub</param>
        [OperationContract]
        void BeginEntryCreate(IInfoEntry entry);
    }

    /// <summary>
    /// Arguments of the IInfoSource.ExecuteCommand member
    /// </summary>
    [ServiceContract(Namespace = "http://InfFront.UICore")]
    public interface IExecuteCommandArgs
    {
        /// <summary>
        /// Get the Command to be executed
        /// </summary>
        /// <returns>the command</returns>
        [OperationContract]
        IInfoCommand GetCommand();

        /// <summary>
        /// Get the entry currently selected
        /// </summary>
        /// <returns>the entry</returns>
        [OperationContract]
        IInfoEntry GetCurrentEntry();
    }

    /// <summary>
    /// The IInfoSource.SetCallbacks action kind
    /// </summary>
    public enum SourceSetCallbacksActionKind { Register, Unregister }

    /// <summary>
    /// Arguments of the IInfoSource.SetCallbacks member
    /// </summary>
    [ServiceContract(Namespace = "http://InfFront.UICore")]
    public interface IInfoSourceSetCallbacksArgs
    {
        /// <summary>
        /// What to do during the SetCallbacks call
        /// </summary>
        [OperationContract]
        SourceSetCallbacksActionKind GetAction();

        /// <summary>
        /// callback to be added or removed
        /// </summary>
        [OperationContract]
        IInfoSourceCallbacks GetCallbacks();
    }

    /// <summary>
    /// IInfoSource enumeration interface
    /// </summary>
    [ServiceContract(Namespace = "http://InfFront.UICore")]
    public interface IInfoSourceList : IContainer<IInfoSource>
    {
    }
}
